package com.lwy.setter2;



import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 填充器工具类
 *
 * @author lwy
 */
@Slf4j
public class Stuffer {

    /**
     * 填充器缓存【K: 填充器类型，V: 填充器实例】
     */
    private static final Map<Class<? extends IStuffer<? extends Annotation>>, IStuffer<? extends Annotation>> STUFFER_CACHE_BY_CLASS = new ConcurrentHashMap<>();

    /**
     * 填充器缓存【K: 填充器名称，V: 填充器实例】
     */
    private static final Map<String, IStuffer<? extends Annotation>> STUFFER_CACHE_BY_NAME = new ConcurrentHashMap<>();

    /* 静态初始化填充器 */
    static {
        STUFFER_CACHE_BY_CLASS.put(StuffEnumImpl.class, new StuffEnumImpl());
    }

    /**
     * 私有构造器
     */
    private Stuffer() {
    }

    /**
     * 填充值
     *
     * @param origin 原始实例
     * @param <T>    泛型
     * @return 原始实例
     */
    public static <T> T stuffValuesWithOne(T origin) {
        if (origin != null) {
            stuffValues(Collections.singleton(origin));
        }
        return origin;
    }

    /**
     * 填充值
     *
     * @param origins 原始集合
     * @param <T>     泛型
     * @return 原始集合
     */
    public static <T> List<T> stuffValuesWithList(List<T> origins) {
        stuffValues(origins);
        return origins;
    }

    /**
     * 填充值
     *
     * @param origins 原始集合
     * @param <T>     泛型
     */
    @SuppressWarnings("unchecked")
    public static <T> void stuffValues(Collection<T> origins) {
        if (CollUtil.isEmpty(origins)) {
            return;
        }
        final T notNullItem = CollUtil.filter(origins, Objects::nonNull).stream().findFirst().orElse(null);
        if (notNullItem == null) {
            log.info("Stuffer执行失败，元素全为null");
            return;
        }
        if (notNullItem instanceof Collection || notNullItem instanceof Map) {
            log.error("Stuffer执行失败，元素类型不支持集合");
            return;
        }
        // 获取类上的所有字段，包括父类字段
        final Field[] fields = ReflectUtil.getFields(notNullItem.getClass());
        if (fields.length < 1) {
            return;
        }
        // 获取字段上的填充器注解
        final Map<Field, StufferMeta> stufferMetaMap = new HashMap<>();
        final Map<Field, Annotation> stufferAnnotationMap = new HashMap<>();
        for (Field field : fields) {
            Annotation[] annotations = field.getDeclaredAnnotations();
            for (Annotation annotation : annotations) {
                StufferMeta stufferMeta = annotation.annotationType().getAnnotation(StufferMeta.class);
                if (stufferMeta != null) {
                    field.setAccessible(true);
                    stufferMetaMap.put(field, stufferMeta);
                    stufferAnnotationMap.put(field, annotation);
                    break;
                }
            }
        }
        if (stufferMetaMap.isEmpty()) {
            return;
        }
        // 获取填充器注解上的填充器，并调用
        stufferMetaMap.forEach((field, stufferMeta) -> {
            @SuppressWarnings("all") final IStuffer stuffer = getStuffer(stufferMeta);
            if (stuffer == null) {
                return;
            }
            final Annotation annotation = stufferAnnotationMap.get(field);
            try {
                // 调用填充器填充值
                stuffer.stuff(annotation, field, origins);
            } catch (Throwable e) {
                log.error("Stuffer执行异常，填充器执行异常, stufferClass={} stufferName={}, annotation={}", stufferMeta.beanClass(), stufferMeta.beanName(), annotation, e);
            }
        });
    }

    /**
     * 获取填充器实例（如果不存在则创建实例）
     *
     * @param stufferMeta 填充器元注解
     * @return 填充器实例
     */
    public static IStuffer<? extends Annotation> getStuffer(StufferMeta stufferMeta) {
        IStuffer<? extends Annotation> stuffer = getStufferByClass(stufferMeta.beanClass());
        if (stuffer == null) {
            stuffer = getStufferByName(stufferMeta.beanName());
        }
        return stuffer;
    }

    /**
     * 获取填充器，根据类型
     *
     * @param stufferClass 填充器类型
     * @return 填充器
     */
    public static IStuffer<? extends Annotation> getStufferByClass(Class<? extends IStuffer<? extends Annotation>> stufferClass) {
        if (stufferClass == null || StufferMeta.DefaultStuffImpl.class.equals(stufferClass)) {
            return null;
        }
        IStuffer<? extends Annotation> stuffer = STUFFER_CACHE_BY_CLASS.get(stufferClass);
        if (stuffer != null) {
            return stuffer;
        }
        // 从SpringIOC获取填充器
        try {
            stuffer = SpringUtil.getBean(stufferClass);
        } catch (UtilException | NoSuchBeanDefinitionException e) {
            if (e instanceof UtilException) {
                log.info("Stuffer执行异常，IOC容器不存在，stufferClass={}", stufferClass.getName());
            }
            if (e instanceof NoSuchBeanDefinitionException) {
                log.warn("Stuffer执行异常，IOC容器中未找到填充器，stufferClass={}", stufferClass.getName());
            }
            // 反射构造填充器
            try {
                stuffer = ReflectUtil.newInstance(stufferClass);
                stuffer.initialize();
            } catch (Exception ex) {
                log.error("Stuffer执行异常，实例化填充器失败，stufferClass={}", stufferClass.getName(), e);
            }
        } catch (Exception e) {
            log.error("Stuffer执行异常，获取填充器异常，stufferClass={}", stufferClass.getName(), e);
        }
        // 将实例放入缓存
        if (stuffer != null) {
            STUFFER_CACHE_BY_CLASS.put(stufferClass, stuffer);
        }
        return stuffer;
    }

    /**
     * 获取填充器，根据名称
     *
     * @param stufferName 填充器名称
     * @return 填充器
     */
    public static IStuffer<? extends Annotation> getStufferByName(String stufferName) {
        if (StrUtil.isBlank(stufferName)) {
            return null;
        }
        IStuffer<? extends Annotation> stuffer = STUFFER_CACHE_BY_NAME.get(stufferName);
        if (stuffer != null) {
            return stuffer;
        }
        // 从SpringIOC获取填充器
        try {
            stuffer = SpringUtil.getBean(stufferName);
        } catch (UtilException | NoSuchBeanDefinitionException e) {
            if (e instanceof UtilException) {
                log.info("Stuffer执行异常，IOC容器不存在，stufferName={}", stufferName, e);
            }
            if (e instanceof NoSuchBeanDefinitionException) {
                log.warn("Stuffer执行异常，IOC容器中未找到填充器，stufferName={}", stufferName, e);
            }
        } catch (Exception e) {
            log.error("Stuffer执行异常，获取填充器异常，stufferName={}", stufferName, e);
        }
        // 将实例放入缓存
        if (stuffer != null) {
            STUFFER_CACHE_BY_NAME.put(stufferName, stuffer);
        }
        return stuffer;
    }
}
